package com.pubinfo.passbook.data.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.mychain.gov.sdk.GovDataSDK;
import com.alipay.mychain.gov.sdk.base.DecryptAndVerifyUtils;
import com.alipay.mychain.gov.sdk.base.FileResult;
import com.alipay.mychain.gov.sdk.base.GenericResult;
import com.alipay.mychain.gov.sdk.base.HttpClientUtils;
import com.alipay.mychain.gov.sdk.facade.enums.EncryptTpyeEnum;
import com.alipay.mychain.gov.sdk.request.SignedRequest;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.pubinfo.passbook.common.config.ApplicationConfig;
import com.pubinfo.passbook.common.entity.TFileInfo;
import com.pubinfo.passbook.common.entity.TRequestLog;
import com.pubinfo.passbook.common.entity.TSourceInvoice;
import com.pubinfo.passbook.common.entity.TTaskLog;
import com.pubinfo.passbook.common.exception.ServiceException;
import com.pubinfo.passbook.common.mapper.TSubsidiaryPrivateKeyMapper;
import com.pubinfo.passbook.common.mapper.TSystemTaskLogMapper;
import com.pubinfo.passbook.common.model.bo.SubsidiaryInfo;
import com.pubinfo.passbook.common.model.constant.LogNameEnum;
import com.pubinfo.passbook.common.model.dto.tax.QueryByTimeResult;
import com.pubinfo.passbook.common.service.master.TSyncLogService;
import com.pubinfo.passbook.common.utils.tax.Util;
import com.pubinfo.passbook.data.service.InvoiceFilePackageInfoService;
import com.pubinfo.passbook.data.service.TFileInfoService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Slf4j
@Service
public class InvoiceFilePackageInfoServiceImpl implements InvoiceFilePackageInfoService {
  
  @Resource
  private ApplicationConfig config;
  @Autowired
  private TSyncLogService kafkaSender;
  @Autowired
  TFileInfoService fileInfoService;
  @Autowired
  private TSubsidiaryPrivateKeyMapper keyMapper;
  @Autowired
  TSystemTaskLogMapper taskLogMapper;
  
  @Override
    public QueryByTimeResult getInvoiceFilePackageCount(String requestId, String kprq, SubsidiaryInfo info) {
        String nsrsbh = info.getNsrsbh();
        // String kprq = "2021-06-20";
        TRequestLog syncLog = new TRequestLog();
        String gx_falg = "1";
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("authorizedNsrsbh", nsrsbh);
        jsonObject.put("nsrsbh", nsrsbh);
        //  jsonObject.put("kprq", kprq);
        jsonObject.put("jgrq", kprq);
    
    jsonObject.put("gxfbs", gx_falg);
        jsonObject.put("requestId", requestId);
        String jsonStr = JSONObject.toJSONString(jsonObject);
        String signStr = sign(jsonStr, info);
        String url = config.getTax().getApi().getInvoiceFilePackageCount();
    
    syncLog.setType(1).setParam(jsonObject.toJSONString()).setUrl(url).setStatus(2).setName(LogNameEnum.QUERY_BY_TIME.getCode());
    
    QueryByTimeResult timeResult = post(signStr, config.getTax().getUrl() + url, syncLog, 0, info);
    
    //   kafkaSender.save(syncLog);
        return timeResult;
    }
  
  @Override
    public List<TFileInfo> getInvoiceFilePackageInfo(String requestId, Integer pageNumber, SubsidiaryInfo info, String date) throws IOException {
        TRequestLog syncLog = new TRequestLog();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("nsrsbh", info.getNsrsbh());
        jsonObject.put("pageNumber", pageNumber);
        jsonObject.put("requestId", requestId);
        String jsonStr = JSONObject.toJSONString(jsonObject);
        String url = config.getTax().getApi().getInvoiceFilePackageInfo();
    
    syncLog.setType(1).setParam(jsonObject.toJSONString()).setUrl(url).setStatus(2).setName(LogNameEnum.FETCH_PAGE.getCode());
    
    FileResult fileResult = postAndDecryptFile(sign(jsonStr, info), config.getTax().getUrl() + url, syncLog, 0);
        DecryptAndVerifyUtils decryptAndVerifyUtils = new DecryptAndVerifyUtils(info.getNsrsbh(), info.getPassword(), info.getPrivateKey());
    
    byte[] fileData = decryptAndVerifyUtils.decrypt(fileResult);
    
    kafkaSender.save(syncLog);
        //saveOrUpdateBatch()
        return fileInfoService.saveInvoiceFile(fileData,date,info.getNsrsbh());
    }
  
    @Override
    @SneakyThrows
    public List<TFileInfo> listByDate(SubsidiaryInfo info, String date) {
        TTaskLog systemTaskLog = new TTaskLog();
        List<TFileInfo> tFileInfoAll = new ArrayList<>();
        UUID uuid = UUID.randomUUID();
        QueryByTimeResult result = getInvoiceFilePackageCount(uuid.toString(), date, info);
        Integer successCount = 0;
        List<TFileInfo> fileInfos = new ArrayList<>();
        if (result != null && result.getSuccess()) {
            Integer totalPage = result.getData().getTotalPage();
            Long startTime = System.currentTimeMillis();

          if (totalPage > 0) {
            for (int i = 1; i <= totalPage; i++) {
                List<TFileInfo> fileInfoList = getInvoiceFilePackageInfo(uuid.toString(), i, info, date);
                if (!CollectionUtils.isEmpty(fileInfoList)) {
                    successCount += fileInfoList.size();
                }
                fileInfos.addAll(fileInfoList);
            }
          }
        Long endTime = System.currentTimeMillis();
        Integer totalCount = result.getData().getTotalCount();
        systemTaskLog.setStartDate(new SimpleDateFormat("yyyy-MM-dd").parse(date));
        systemTaskLog.setAcceptTotalCount(totalCount);
        systemTaskLog.setSuccessCount(successCount);
        systemTaskLog.setTaskId("1");
        systemTaskLog.setName(info.getName());
        systemTaskLog.setStatus(successCount == totalCount ? 0 : 1);
        systemTaskLog.setResponseTime(endTime - startTime);
        // systemTaskLog.setId(IdWorker.get32UUID());
        taskLogMapper.insert(systemTaskLog);
        //taskLogService.sendTaskLogSave(systemTaskLog);
        tFileInfoAll.addAll(fileInfos);
        log.info(date + "日" + info.getName() + ",总共" + totalCount + "条数据");
        }
    
    return tFileInfoAll;
    }
  
  @Override
    public Integer saveByDateAndTaskId(String date,String taskId) {
    
    List<SubsidiaryInfo> infoList = keyMapper.listTaxAllSubsidiaryInfo(null);
        //一次性提交保存
        Integer count = 0;
        List<TFileInfo> invoiceListAll = new ArrayList<>();
        if (!CollectionUtils.isEmpty(infoList)) {
            Long startDate = System.currentTimeMillis();
            for (SubsidiaryInfo info : infoList) {
                invoiceListAll.addAll(listByDate(info, date));
            }
            log.info("数据获取时间" + (System.currentTimeMillis() - startDate) + "ms");
        }
    
    Long startDate = System.currentTimeMillis();
        log.info("sql执行时间" + (System.currentTimeMillis() - startDate) + "ms");
        count += invoiceListAll.size();
        return count;
    }

    @Override
    public void sync(String taskId) {
        //取上一天的日期
        String startDate = Util.getTaxOnTheDay();
        saveByDateAndTaskId(startDate, taskId);
    }

    @SneakyThrows
    @Override
    public Integer sync(String startDate, String endDate) {
        List<String> dateList = Util.getTaxTwoDaysDay(startDate, endDate);
        TTaskLog systemTaskLog = new TTaskLog();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date start = sdf.parse(startDate);
        Date end = sdf.parse(endDate);
        systemTaskLog.setStartDate(start);
        systemTaskLog.setEndDate(end);
        Integer totalCount = 0;
        if (!CollectionUtils.isEmpty(dateList)) {
            for (String date : dateList) {
                totalCount += saveByDateAndTaskId(date,null);
            }
        }
        systemTaskLog.setName("all");
        systemTaskLog.setAcceptTotalCount(totalCount);
        systemTaskLog.setTaskId("1");

        taskLogMapper.insert(systemTaskLog);
        log.info("总批量入库:" + totalCount + "条数据");
        return totalCount;
    }


  public String sign(String jsonStr, SubsidiaryInfo info) {
    
    GovDataSDK.getInstance().init(info.getNsrsbh(), info.getPrivateKey(), info.getPassword(), EncryptTpyeEnum.SM4);
        SignedRequest request1 = null;
        try {
            request1 = GovDataSDK.getInstance().getRequestBuilder().generateSignedPayload(jsonStr);
        } catch (Exception e) {
            //log.info("数据:"+info+"异常"+e);
            throw new ServiceException("数据:" + info + "异常" + e);
        }
    
    return JSON.toJSONString(request1);
    }
  
  public QueryByTimeResult post(String jsonStr, String uri, TRequestLog syncLog, Integer count, SubsidiaryInfo info) {
        String response = null;
        try {
            response = HttpClientUtils.doPost(uri, jsonStr, ContentType.APPLICATION_JSON);
        } catch (Exception e) {
            log.error("访问省税务接口失败!", e);
        }
        QueryByTimeResult pageResult = JSON.parseObject(response, QueryByTimeResult.class);
        //先保存日志 重试三次
        Boolean success = null;
        if (StringUtils.isEmpty(pageResult) || !pageResult.getSuccess()) {
            count++;
            try {
                Thread.sleep( 200 );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count <= 3) {
                post(jsonStr, uri, syncLog, count, info);
            } else {
                syncLog.setStatus(0);
                log.error(syncLog.getName() + "失败:数据:" + pageResult);
            }
        } else {
            success = pageResult.getSuccess();
            syncLog.setData(JSONObject.toJSONString(pageResult));
            if (!success) {
                String msg = pageResult.getErrorMsg();
                syncLog.setStatus(0);
                log.error(syncLog.getName() + "请求数据" + JSONObject.toJSON(syncLog.getParam()) + "认证数据" + JSONObject.toJSON(info) + "失败:" + msg + " 数据:" + JSONObject.toJSON(pageResult));
                kafkaSender.save(syncLog);
            }
        }
    
    return pageResult;
    }
  
  public FileResult postAndDecryptFile(String jsonStr, String uri, TRequestLog syncLog, Integer count) {
        // 获取密文和签名集合
        String response = null;
    
    try {
      
      response = HttpClientUtils.doPost(uri, jsonStr, ContentType.APPLICATION_JSON);
      
    } catch (Exception e) {
            e.printStackTrace();
        }
    
    GenericResult result = JSON.parseObject(response, GenericResult.class);
        if (StringUtils.isEmpty(result) || !result.getSuccess()) {
            count++;
            try {
                Thread.sleep( 200 );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count <= 3) {
                postAndDecryptFile(jsonStr, uri, syncLog, count);
            } else {
                syncLog.setStatus(0);
                log.error(syncLog.getName() + "失败:数据:" + result);
            }
        }
        // System.out.println(result);
      FileResult fileResult = JSONObject.parseObject(result.getData(), FileResult.class);
        // logService.save(syncLog);
    
    return fileResult;
    }
}
